#ifndef __CC_ABS_DEVICE__
#define __CC_ABS_DEVICE__

#include "cc_portable.h"
#include "cc_core.h"
#include "cc_log.h"

typedef enum
{
  DEVICE_EOK = 0,
  DEVICE_EHARD_DRV_NULL,
  DEVICE_ENULL
} e_device_err;

typedef enum
{
  CC_DEVICE_TYPE_UNKNOW = 0,
  CC_DEVICE_TYPE_SERVO,
  CC_DEVICE_TYPE_LED,
  CC_DEVICE_TYPE_SCALE,
  CC_DEVICE_TYPE_THERMOMETER,
  CC_DEVICE_TYPE_PHOTOSENSITIVE,
  CC_DEVICE_TYPE_INFRARED,

  // 在这个前面注册设备类型
  CC_DEVICE_TYPE_MAX,
} e_device_type;

typedef e_device_err (*device_init_cb)(void* user_data);
// 操作完成的回调 例如读取完成需要往mqtt服务器发送消息 就可以注册该回调
// 数据流向 mqtt服务器下发读指令,分发至设备读时,设备读取完成,调用回调往mqtt回复消息
typedef e_device_err (*device_exe_exit_cb)(void* user_data);
// type用来指定一些特定操作 data是用户可以指定的自定义参数
typedef e_device_err (*device_read_cb)(void* user_data, const char* msg, int type, void* data);
typedef e_device_err (*device_write_cb)(void* user_data, const char* msg, int type, void* data);
typedef e_device_err (*device_control_cb)(void* user_data, const char* msg, int type, void* data);

typedef struct
{
  void* hard_drv;
  int device_type;
  int device_id;
  int pin[4];
  // 用于存当前设备的一些数值量 整型就强转
  float num_data[CC_CONFIG_DEVICE_MAX_NUM_DATA];
  int state;
  char read_buf[CC_CONFIG_DEVICE_MAX_READ_BUFF];

  // 用户记得free数据
  device_init_cb init_cb;
  device_read_cb read_cb;
  device_write_cb write_cb;
  device_control_cb control_cb;

  device_exe_exit_cb read_exit_cb;
  device_exe_exit_cb write_exit_cb;
  device_exe_exit_cb control_exit_cb;

  cc_mutex mutex;
  cc_que mqtt_queue;
  uint8_t mqtt_queue_storage_arr[GET_QUEUE_STORAGE_SIZE(CC_CONFIG_DEVICE_QUEUE_LENGTH, CC_CONFIG_DEVICE_QUEUE_SIZE)];

} user_device, *user_device_t;

struct cc_device_init_node
{
  uint8_t device_type;
  device_init_cb afunc;
};

void cc_device_init_mount(device_init_cb func, int device_type);

// 挂载一个初始化回调 用于自动初始化时，能为对应类型的设备设置正确的回调函数
#define CC_DEVICE_INIT_MOUNT(func, type)                                          \
  static void __attribute__((constructor)) cc_device_cb_init_register##func(void) \
  {                                                                               \
    cc_device_init_mount(func, type);                                             \
  }

user_device_t cc_device_get(user_device_t devices, uint8_t device_type, uint8_t device_id);

#endif